﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Xeml.Document;
using Xeml.Document.Contracts;
using Xeml.Sampling.Contracts;
using ComponentFactory.Krypton.Toolkit;
using System.Threading.Tasks;

namespace Xid.Controls.SampleCompiler
{
    public partial class DataMappingCtrl : UserControl
    {
        IDocument _xemlDoc;
        DataProviderResource _provider;
        SampleMappings _mappings = new SampleMappings();

        public DataMappingCtrl()
        {
            InitializeComponent();
            sampleMappingBindingSource.DataSource = _mappings;
            fkmPanelCtrl1.KeyMapCtrl.KeyMapChanged += new EventHandler(KeyMapCtrl_KeyMapChanged);
        }

        void KeyMapCtrl_KeyMapChanged(object sender, EventArgs e)
        {
            if (kryptonDataGridView1.SelectedCells.Count > 0)
            {
                if (!_xemlDoc.ProviderDataMappings.ContainsKey(_provider.FriendlyName))
                {
                    _xemlDoc.ProviderDataMappings.Add(_provider.FriendlyName, new DataMappings());

                }

                kryptonDataGridView1.Rows[kryptonDataGridView1.SelectedCells[0].RowIndex].Cells["foreignKeyMappingDataGridViewTextBoxColumn"].Value = fkmPanelCtrl1.KeyMap;

                SampleMapping sm = kryptonDataGridView1.Rows[kryptonDataGridView1.SelectedCells[0].RowIndex].DataBoundItem as SampleMapping;

                if (!_xemlDoc.ProviderDataMappings[_provider.FriendlyName].Contains(sm.SampleId))
                {
                    _xemlDoc.ProviderDataMappings[_provider.FriendlyName].Add(sm.SidMapping);
                }
                sm.LookUp = _provider.Provider.Validate(sm.SidMapping);
                kryptonDataGridView1.Refresh();
            }
        }

        public void Setup(IDocument xemlDoc, DataProviderResource prov)
        {
            _xemlDoc = xemlDoc;
            _provider = prov;
            if (_provider != null && _provider.ComponentState == ComponentLoadState.Loaded)
            {
                ForeignKeyMap fkm = new ForeignKeyMap();
                foreach (var item in _provider.Provider.ListForeignKey())
                {
                    fkm.Add(item, string.Empty);
                }
                fkmPanelCtrl1.KeyMapCtrl.Setup(_provider);
                fkmPanelCtrl1.KeyMapCtrl.KeyMapProtoType = fkm;
            }

            sampleMappingBindingSource.DataSource = new List<SampleMapping>();

            if (_xemlDoc != null)
            {
                string provname = string.Empty;
                if (_provider != null)
                {
                    provname = _provider.FriendlyName;

                    kryptonDataGridView1.Enabled = true;
                    buttonSpecAutoMap.Enabled = (_provider.ComponentState == ComponentLoadState.Loaded && _provider.Provider.SupportsAutoMapping) ? ButtonEnabled.True : ButtonEnabled.False;

                    var samples = DocumentHelper.ExtractSamples(_xemlDoc);

                    List<SidMapping> sidmappings = new List<SidMapping>();
                    if (_xemlDoc.ProviderDataMappings.ContainsKey(_provider.FriendlyName))
                    {
                        sidmappings = _xemlDoc.ProviderDataMappings[_provider.FriendlyName].ToList();
                    }

                    foreach (SampleMapping sm in samples.OrderBy(x => x.Id).Select(x => new SampleMapping(new SidMapping(x.Id))))
                    {
                        SidMapping sid = sidmappings.FirstOrDefault(x => x.SampleId == sm.SampleId);
                        if (sid != null)
                        {
                            sm.SidMapping = sid;
                            sm.LookUp = _provider.Provider.Validate(sid);
                        }
                        sampleMappingBindingSource.Add(sm);
                    }
                }
                else
                {
                    kryptonDataGridView1.Enabled = false;
                    // kryptonButtonAutomap.Enabled = false;
                }
                kryptonDataGridView1.Refresh();
            }
        }

        private void kryptonButtonAutomap_Click(object sender, EventArgs e)
        {
            var sampleids = Xeml.Document.DocumentHelper.ExtractSamples(_xemlDoc).Select(x => x.Id).OrderBy(y => y);
            var sids = _provider.Provider.AutoMap(_xemlDoc.Id, _xemlDoc.Name, sampleids);
            if (sids.Count() > 0)
            {
                var mappings = sids.Select(x => new SampleMapping(x, _provider.Provider.Validate(x)));

                sampleMappingBindingSource.DataSource = mappings;
                sampleMappingBindingSource.ResetBindings(false);

                kryptonDataGridView1.Refresh();

                if (!_xemlDoc.ProviderDataMappings.ContainsKey(_provider.FriendlyName))
                {
                    _xemlDoc.ProviderDataMappings.Add(_provider.FriendlyName, new DataMappings());
                }
                _xemlDoc.ProviderDataMappings[_provider.FriendlyName].Clear();
                foreach (var sid in sids)
                {
                    //sid.ForeignKeyMap = "";
                    if (!_xemlDoc.ProviderDataMappings[_provider.FriendlyName].Contains(sid))
                        _xemlDoc.ProviderDataMappings[_provider.FriendlyName].Add(sid);
                }
            }
        }

        private void kryptonDataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (e.ColumnIndex == 1)
            {
                SidLookUpResult lp = (SidLookUpResult)kryptonDataGridView1.Rows[e.RowIndex].Cells[0].Value;
                switch (lp)
                {
                    case SidLookUpResult.UnknownSample:
                        goto default;
                    case SidLookUpResult.UnsupportedMapping:
                        {
                            e.Value = Properties.Resources.Error;
                            break;
                        }
                    case SidLookUpResult.Valid:
                        {
                            e.Value = Properties.Resources.OK;
                            break;
                        }
                    default:
                        {
                            e.Value = Properties.Resources.Unknown;
                            break;
                        }
                }
            }
        }

        private void kryptonDataGridView1_SelectionChanged(object sender, EventArgs e)
        {
            if (kryptonDataGridView1.SelectedCells.Count > 0)
            {
                fkmPanelCtrl1.FkmTop = this.kryptonDataGridView1.GetCellDisplayRectangle(3, kryptonDataGridView1.SelectedCells[0].RowIndex, false).Top;
                ForeignKeyMap current = ((kryptonDataGridView1.CurrentRow as DataGridViewRow).DataBoundItem as SampleMapping).ForeignKeyMapping;
                if (current.Count == 0 && LastUsedKeyMapping != null)
                {
                    foreach (var item in LastUsedKeyMapping)
                    {
                        current.Add(item.Key, item.Value);
                    }
                }
                fkmPanelCtrl1.KeyMap = current;
            }
        }

        private void kryptonDataGridView1_Scroll(object sender, ScrollEventArgs e)
        {
            if (kryptonDataGridView1.SelectedCells.Count > 0)
            {
                fkmPanelCtrl1.FkmTop = this.kryptonDataGridView1.GetCellDisplayRectangle(3, kryptonDataGridView1.SelectedCells[0].RowIndex, false).Top;
            }
        }

        private void buttonSpecClearMapping_Click(object sender, EventArgs e)
        {
            foreach (var item in kryptonDataGridView1.SelectedRows)
            {
                SampleMapping sm = (item as DataGridViewRow).DataBoundItem as SampleMapping;
                sm.SidMapping.ForeignKeyMap.Clear();
                sm.LookUp = SidLookUpResult.UnknownSample;
            }

            sampleMappingBindingSource.ResetBindings(false);
        }

        ForeignKeyMap LastUsedKeyMapping = null;

        private void kryptonDataGridView1_RowLeave(object sender, DataGridViewCellEventArgs e)
        {
            LastUsedKeyMapping = ((sender as KryptonDataGridView).Rows[e.RowIndex].DataBoundItem as SampleMapping).ForeignKeyMapping;
        }

        internal void OnSelectedObservationPointChanged(object sender, Xeml.Document.XemlEventArgs.ObservationPointSelectedEventArgs e)
        {
            kryptonDataGridView1.CurrentCell = null;
            kryptonDataGridView1.ClearSelection();

            List<int> SampleIDsFromObservation = new List<int>();

            if (e.myObservationPoint != null && e.myObservationPoint.Observations != null && e.myObservationPoint.Observations.FirstOrDefault() != null)
            {
                foreach (var observation in e.myObservationPoint.Observations)
                {
                    foreach (var partition in observation.Partitions)
                    {
                        SampleIDsFromObservation.Add(partition.GetSample().Id);
                    }
                }
            }

            SampleIDsFromObservation.Sort();

            foreach (var item in kryptonDataGridView1.Rows)
            {
                if (SampleIDsFromObservation.BinarySearch(((item as DataGridViewRow).DataBoundItem as SampleMapping).SampleId) >= 0)
                {
                    (item as DataGridViewRow).Visible = true;
                }
                else
                {
                    (item as DataGridViewRow).Visible = false;
                }
            }
        }

        private void kryptonDataGridView1_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
        {
            KryptonDataGridView dgv = sender as KryptonDataGridView;
            for (int i = 0; i < e.RowCount; i++)
            {
                Sample s = _xemlDoc.GetSample((dgv.Rows[e.RowIndex + i].DataBoundItem as Xid.Controls.SampleMapping).SampleId);
                dgv.Rows[e.RowIndex + i].Cells["Germplasm"].Value = s.GetGermDescription();
                dgv.Rows[e.RowIndex + i].Cells["Material"].Value = s.GetMaterialDescription();
                dgv.Rows[e.RowIndex + i].Cells["DevelopmentalStage"].Value = s.GetDevelopmentalStageDescription();
            }
        }

        private void btnPasteMapping_Click(object sender, EventArgs e)
        {
            //kryptonDataGridView1.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableAlwaysIncludeHeaderText;
            //kryptonDataGridView1.SelectAll();
            //Clipboard.SetDataObject(kryptonDataGridView1.GetClipboardContent(), true);

            if (!_xemlDoc.ProviderDataMappings.ContainsKey(_provider.FriendlyName))
            {
                _xemlDoc.ProviderDataMappings.Add(_provider.FriendlyName, new DataMappings());
            }

            try
            {
                if (Clipboard.ContainsData(DataFormats.Text))
                {
                    using (System.IO.StringReader reader = new System.IO.StringReader(System.Windows.Forms.Clipboard.GetText()))
                    {
                        ProcessReader(reader, "\t");
                    }
                }
                else if (Clipboard.ContainsData(DataFormats.CommaSeparatedValue))
                {
                    IDataObject clipboardData = Clipboard.GetDataObject();
                    using (System.IO.StreamReader reader = new System.IO.StreamReader(clipboardData.GetData(DataFormats.CommaSeparatedValue) as System.IO.Stream, System.Text.Encoding.GetEncoding(1252)))
                    {
                        ProcessReader(reader, ",");
                    }
                }
                else
                {
                    throw new Exception("No clipboard data available or data in wrong format, expecting comma separated values or text with tab separated values");
                }
            }
            catch (Exception ex)
            {
                Microsoft.SqlServer.MessageBox.ExceptionMessageBox emb = new Microsoft.SqlServer.MessageBox.ExceptionMessageBox(ex);
                emb.Show(this);
            }
        }

        private void ProcessReader(System.IO.TextReader reader, string separator)
        {
            string[] colValues = reader.ReadLine().Split(separator.ToCharArray());
            Dictionary<string, int> colnames = new Dictionary<string, int>();
            foreach (var item in colValues)
            {
                colnames.Add(item, colnames.Count);
            }

            #region test
            if (!colnames.ContainsKey("SampleId"))
            {
                throw new Exception("missing column 'SampleId'");
            }
            foreach (string ForeignKey in _provider.Provider.ListForeignKey())
            {
                if (!colnames.ContainsKey(ForeignKey))
                {
                    throw new Exception(string.Format("missing column '{0}'", ForeignKey));
                }
            }
            #endregion test

            while (reader.Peek() > 0)
            {
                colValues = reader.ReadLine().Split(separator.ToCharArray());

                DataGridViewRow dgvr = kryptonDataGridView1.Rows.Cast<DataGridViewRow>().SingleOrDefault(x => x.Cells["sampleIdDataGridViewTextBoxColumn"].Value.ToString() == colValues[colnames["SampleId"]]);

                if (dgvr != null)
                {
                    SampleMapping sm = dgvr.DataBoundItem as SampleMapping;
                    ForeignKeyMap map = sm.ForeignKeyMapping;
                    //sm.ForeignKeyMapping.Clear(); this here is very wired
                    map.Clear();
                    if (_provider.Provider.ListForeignKey().All(x => !string.IsNullOrEmpty(colValues[colnames[x]].Trim())))
                    {
                        foreach (string ForeignKey in _provider.Provider.ListForeignKey())
                        {
                            map.Add(ForeignKey, colValues[colnames[ForeignKey]]);
                        }
                    }

                    dgvr.Cells["foreignKeyMappingDataGridViewTextBoxColumn"].Value = map;
                    if (!_xemlDoc.ProviderDataMappings[_provider.FriendlyName].Contains(sm.SampleId))
                    {
                        _xemlDoc.ProviderDataMappings[_provider.FriendlyName].Add(sm.SidMapping);
                    }

                    sm.LookUp = _provider.Provider.Validate(sm.SidMapping);
                }
            }
            sampleMappingBindingSource.ResetBindings(false);
            kryptonDataGridView1.Refresh();
        }
    }
}
